#include "genetico.h"


Genetico::Genetico () {}

/** Constructor
* @param listado de los rectángulos a empaquetar
  @param contenedor
* */
Genetico::Genetico( list <Rectangulo> lista, Contenedor & C_): Heuristica (lista) {
  	srand((unsigned)time(0));
   media = (double) INT_MAX;
   cout << "Genetico::Constructor(listado) con lista de tamaño= " << lista.size() << endl;
   candidatos = lista;
   iteracion =  iteracionSinCambio = 0;
          mejorSol = INT_MAX;
   if (lista.size() <=10) 
     N = lista.size()/2;
   else
     N = lista.size()*20/100;
   cout << "El número de individuos será = " << N << endl;
   C = C_;
}

void Genetico::generar_probabilidades () {
	double valor_total = 0.0;
	// Calcular la suma total.
	for (int i = 0; i < N; i++) {
	   valor_total += 1.0 / Individuo[i].getValor();
   }
   // Calculo las probabilidades.
	double valor = 0.0;
   for (int i = 0; i < N; i++) {
      double aux = (1.0/ Individuo[i].getValor());
	  valor += (aux / valor_total);
      p.push_back (valor);
   }
}

int Genetico:: elegido() {

	double aleatorio = ((double) rand()/ double (RAND_MAX));
	for (int i = 0; i < N; i++) {
       if ( p[i] >= aleatorio) {
          return i;
       }
    }
    return (0);
}

bool Genetico::parada(int valor) {
   iteracion++;
   if (valor < mejorSol) {
      mejorSol = valor;
      mejor = solucion;
      iteracionSinCambio = 0;
   } else {
      iteracionSinCambio++;
      new_media = 0.0;
      for (int i = 0; i < Individuo.size(); i++)
         new_media += (double)Individuo[i].getValor();
      new_media = new_media / Individuo.size();
      if (media > new_media) {
	      media = new_media;
	      iteracionSinCambio = 0;
      }
   }
   if (iteracion == MAX_ITERACIONES) {
      cout << "Alcanzado máximo de iteraciones: " << MAX_ITERACIONES  << endl;
         return true;
   }
   if (iteracionSinCambio == MAX_ITERACIONES_SIN_CAMBIO) {
      cout << "Alcanzado máximo de iteraciones sin mejora: " << MAX_ITERACIONES_SIN_CAMBIO << endl;
      return true;
   }
   
   return false;
}

list<Rectangulo> Genetico::generaInicial() {
  // Vamos a generar aleatoriamente n soluciones.
   Individuo = generaConjuntoSoluciones(N);
   // Calculo su Altura y selecciono la mejor de todas.
   int i;
   for (i = 0; i < N; i++) {
      int valor = C.calcularAltura(Individuo[i].getLista());
      Individuo[i].setValor(valor);
   }
   // Ordenamos las soluciones según su valor.
   sort(Individuo.begin(), Individuo.end());
   solucion = Individuo[0].getLista();
   return (solucion);
}



list<Rectangulo> Genetico::mejoraSolucion() {
   generar_probabilidades();
   // Hacemos emparejamientos de la mitad de la población.
   int x = N/4;
   for (int i = 0; i < x; i++) {
      int padre = elegido();
      int madre;
      do {
        madre = elegido();
      }while (padre == madre);
      int tam = Individuo[padre].getLista().size();
      Nueva_generacion.push_back(combinaSoluciones(Individuo[padre], Individuo[madre], (tam/2), 0));
   }
   // Mutamos mitad de la población.
   for (int j = 0; j < N/2; j++) {
      int r = rand() %N;
	  Solucion s = MutarSolucion(Individuo[r]);
	  int valor = C.calcularAltura(s.getLista());
      s.setValor(valor);
	  Nueva_generacion.push_back(s);
   }
   // Competición
   // Lo que haremos será colocar todos los datos en Individuos
   // Ordenar y destruir hasta que la población sea igual que la anterior.
   for (int i = 0; i < Nueva_generacion.size(); i++)
      Individuo.push_back(Nueva_generacion[i]);
   sort(Individuo.begin(), Individuo.end());
   for (int i = 0; i < Nueva_generacion.size(); i++)
      Individuo.pop_back();
   Nueva_generacion.clear();
   solucion = Individuo[0].getLista();
   return (solucion);
}